apiVersion: v1
kind: Namespace
metadata:
  name: unidesk
  labels:
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/k3s-cluster: unidesk-k3s
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: code-queue-read
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: read
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
    unidesk.ai/instance-id: D601-read
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: code-queue
      app.kubernetes.io/component: read
      unidesk.ai/instance-id: D601-read
  template:
    metadata:
      labels:
        app.kubernetes.io/name: code-queue
        app.kubernetes.io/component: read
        app.kubernetes.io/part-of: unidesk
        unidesk.ai/deployment-mode: k3sctl-managed
        unidesk.ai/instance-id: D601-read
        unidesk.ai/node-id: D601
    spec:
      nodeSelector:
        unidesk.ai/node-id: D601
      terminationGracePeriodSeconds: 30
      containers:
        - name: code-queue
          image: unidesk-code-queue:d601
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 4222
          envFrom:
            - secretRef:
                name: code-queue-env
                optional: true
          env:
            - name: HOST
              value: "0.0.0.0"
            - name: PORT
              value: "4222"
            - name: DATABASE_URL
              value: "postgres://unidesk:unidesk_dev_password@d601-tcp-egress-gateway.unidesk.svc.cluster.local:15432/unidesk"
            - name: CODE_QUEUE_INSTANCE_ID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: CODE_QUEUE_SERVICE_ROLE
              value: "read"
            - name: CODE_QUEUE_SCHEDULER_ENABLED
              value: "false"
            - name: CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED
              value: "false"
            - name: CODE_QUEUE_DATA_DIR
              value: "/var/lib/unidesk/code-queue"
            - name: CODE_QUEUE_WORKDIR
              value: "/workspace"
            - name: CODE_QUEUE_CODEX_HOME
              value: "/var/lib/unidesk/code-queue/codex-home"
            - name: CODE_QUEUE_OPENCODE_XDG_DIR
              value: "/var/lib/unidesk/code-queue/opencode-xdg"
            - name: CODE_QUEUE_SOURCE_CODEX_CONFIG
              value: "/root/.codex/config.toml"
            - name: UNIDESK_SKILLS_PATH
              value: "/root/.agents/skills"
            - name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
              value: "/home/ubuntu/.agents/skills"
            - name: CODE_QUEUE_DEFAULT_MODEL
              value: "gpt-5.5"
            - name: CODE_QUEUE_MODELS
              value: "gpt-5.5,gpt-5.4-mini,gpt-5.4,deepseek-chat,minimax-m3,minimax-m2.7"
            - name: MINIMAX_MODEL
              value: "MiniMax-M3"
            - name: MINIMAX_M3_MODEL
              value: "MiniMax-M3"
            - name: CODE_QUEUE_MODEL_REASONING_EFFORTS
              value: "gpt-5.5=xhigh"
            - name: CODE_QUEUE_SANDBOX
              value: "danger-full-access"
            - name: CODE_QUEUE_APPROVAL_POLICY
              value: "never"
            - name: CODE_QUEUE_MAX_ACTIVE_QUEUES
              value: "0"
            - name: CODE_QUEUE_DATABASE_POOL_MAX
              value: "2"
            - name: NODE_OPTIONS
              value: "--max-old-space-size=512"
            - name: GIT_CONFIG_COUNT
              value: "1"
            - name: GIT_CONFIG_KEY_0
              value: "safe.directory"
            - name: GIT_CONFIG_VALUE_0
              value: "*"
            - name: CODE_QUEUE_IN_MEMORY_OUTPUT_RECORDS
              value: "10"
            - name: CODE_QUEUE_IN_MEMORY_EVENT_RECORDS
              value: "10"
            - name: CODE_QUEUE_MAIN_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_REMOTE_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EXECUTION_PROVIDER_IDS
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_MASTER_HOST
              value: "74.48.78.17"
            - name: CODE_QUEUE_DEV_CONTAINER_DEFAULT_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EGRESS_PROXY_ENABLED
              value: "false"
            - name: CODE_QUEUE_EGRESS_PROXY_URL
              value: ""
            - name: CODE_QUEUE_EGRESS_PROXY_NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: HTTP_PROXY
              value: ""
            - name: HTTPS_PROXY
              value: ""
            - name: ALL_PROXY
              value: ""
            - name: http_proxy
              value: ""
            - name: https_proxy
              value: ""
            - name: all_proxy
              value: ""
            - name: NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: no_proxy
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: OA_EVENT_FLOW_BASE_URL
              value: "http://d601-tcp-egress-gateway.unidesk.svc.cluster.local:4255"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
              value: "false"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL
              value: ""
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE
              value: "private"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_USER_ID
              value: "645275593"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_MAX_RESPONSE_CHARS
              value: "12000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TIMEOUT_MS
              value: "15000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_SEND_ATTEMPTS
              value: "3"
            - name: LOG_FILE
              value: "/var/log/unidesk/code-queue-read.jsonl"
            - name: UNIDESK_LOG_RETENTION_BYTES
              value: "1GiB"
          volumeMounts:
            - name: docker-sock
              mountPath: /var/run/docker.sock
            - name: workspace
              mountPath: /workspace
            - name: workspace
              mountPath: /home/ubuntu
            - name: repo
              mountPath: /root/unidesk
            - name: repo
              mountPath: /app
            - name: codex-config
              mountPath: /root/.codex/config.toml
              readOnly: true
            - name: codex-auth
              mountPath: /root/.codex/auth.json
              readOnly: true
            - name: skills-dir
              mountPath: /root/.agents/skills
              readOnly: true
            - name: ssh-dir
              mountPath: /root/.ssh
              readOnly: true
            - name: logs
              mountPath: /var/log/unidesk
            - name: state
              mountPath: /var/lib/unidesk/code-queue
          readinessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 20
          livenessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
          startupProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 60
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              memory: 1Gi
      volumes:
        - name: docker-sock
          hostPath:
            path: /var/run/docker.sock
            type: Socket
        - name: workspace
          hostPath:
            path: /home/ubuntu
            type: Directory
        - name: repo
          hostPath:
            path: /home/ubuntu/cq-deploy
            type: Directory
        - name: codex-config
          hostPath:
            path: /home/ubuntu/.codex/config.toml
            type: File
        - name: codex-auth
          hostPath:
            path: /home/ubuntu/.codex/auth.json
            type: File
        - name: skills-dir
          hostPath:
            path: /home/ubuntu/.agents/skills
            type: Directory
        - name: ssh-dir
          hostPath:
            path: /home/ubuntu/.ssh
            type: Directory
        - name: logs
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue/logs
            type: DirectoryOrCreate
        - name: state
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue
            type: DirectoryOrCreate
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: code-queue-write
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: write
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
    unidesk.ai/instance-id: D601-write
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: code-queue
      app.kubernetes.io/component: write
      unidesk.ai/instance-id: D601-write
  template:
    metadata:
      labels:
        app.kubernetes.io/name: code-queue
        app.kubernetes.io/component: write
        app.kubernetes.io/part-of: unidesk
        unidesk.ai/deployment-mode: k3sctl-managed
        unidesk.ai/instance-id: D601-write
        unidesk.ai/node-id: D601
    spec:
      nodeSelector:
        unidesk.ai/node-id: D601
      terminationGracePeriodSeconds: 30
      containers:
        - name: code-queue
          image: unidesk-code-queue:d601
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 4222
          envFrom:
            - secretRef:
                name: code-queue-env
                optional: true
          env:
            - name: HOST
              value: "0.0.0.0"
            - name: PORT
              value: "4222"
            - name: DATABASE_URL
              value: "postgres://unidesk:unidesk_dev_password@d601-tcp-egress-gateway.unidesk.svc.cluster.local:15432/unidesk"
            - name: CODE_QUEUE_INSTANCE_ID
              value: "D601-write"
            - name: CODE_QUEUE_SERVICE_ROLE
              value: "write"
            - name: CODE_QUEUE_SCHEDULER_ENABLED
              value: "false"
            - name: CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED
              value: "false"
            - name: CODE_QUEUE_DATA_DIR
              value: "/var/lib/unidesk/code-queue"
            - name: CODE_QUEUE_WORKDIR
              value: "/workspace"
            - name: CODE_QUEUE_CODEX_HOME
              value: "/var/lib/unidesk/code-queue/codex-home"
            - name: CODE_QUEUE_OPENCODE_XDG_DIR
              value: "/var/lib/unidesk/code-queue/opencode-xdg"
            - name: CODE_QUEUE_SOURCE_CODEX_CONFIG
              value: "/root/.codex/config.toml"
            - name: UNIDESK_SKILLS_PATH
              value: "/root/.agents/skills"
            - name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
              value: "/home/ubuntu/.agents/skills"
            - name: CODE_QUEUE_DEFAULT_MODEL
              value: "gpt-5.5"
            - name: CODE_QUEUE_MODELS
              value: "gpt-5.5,gpt-5.4-mini,gpt-5.4,deepseek-chat,minimax-m3,minimax-m2.7"
            - name: MINIMAX_MODEL
              value: "MiniMax-M3"
            - name: MINIMAX_M3_MODEL
              value: "MiniMax-M3"
            - name: CODE_QUEUE_MODEL_REASONING_EFFORTS
              value: "gpt-5.5=xhigh"
            - name: CODE_QUEUE_SANDBOX
              value: "danger-full-access"
            - name: CODE_QUEUE_APPROVAL_POLICY
              value: "never"
            - name: CODE_QUEUE_MAX_ACTIVE_QUEUES
              value: "0"
            - name: CODE_QUEUE_DATABASE_POOL_MAX
              value: "2"
            - name: NODE_OPTIONS
              value: "--max-old-space-size=768"
            - name: GIT_CONFIG_COUNT
              value: "1"
            - name: GIT_CONFIG_KEY_0
              value: "safe.directory"
            - name: GIT_CONFIG_VALUE_0
              value: "*"
            - name: CODE_QUEUE_IN_MEMORY_OUTPUT_RECORDS
              value: "10"
            - name: CODE_QUEUE_IN_MEMORY_EVENT_RECORDS
              value: "10"
            - name: CODE_QUEUE_MAIN_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_REMOTE_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EXECUTION_PROVIDER_IDS
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_MASTER_HOST
              value: "74.48.78.17"
            - name: CODE_QUEUE_DEV_CONTAINER_DEFAULT_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EGRESS_PROXY_ENABLED
              value: "false"
            - name: CODE_QUEUE_EGRESS_PROXY_URL
              value: ""
            - name: CODE_QUEUE_EGRESS_PROXY_NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: HTTP_PROXY
              value: ""
            - name: HTTPS_PROXY
              value: ""
            - name: ALL_PROXY
              value: ""
            - name: http_proxy
              value: ""
            - name: https_proxy
              value: ""
            - name: all_proxy
              value: ""
            - name: NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: no_proxy
              value: "localhost,127.0.0.1,::1,host.docker.internal,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,backend-core,oa-event-flow,database"
            - name: OA_EVENT_FLOW_BASE_URL
              value: "http://d601-tcp-egress-gateway.unidesk.svc.cluster.local:4255"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
              value: "false"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL
              value: ""
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE
              value: "private"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_USER_ID
              value: "645275593"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_MAX_RESPONSE_CHARS
              value: "12000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TIMEOUT_MS
              value: "15000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_SEND_ATTEMPTS
              value: "3"
            - name: LOG_FILE
              value: "/var/log/unidesk/code-queue-write.jsonl"
            - name: UNIDESK_LOG_RETENTION_BYTES
              value: "1GiB"
          volumeMounts:
            - name: docker-sock
              mountPath: /var/run/docker.sock
            - name: workspace
              mountPath: /workspace
            - name: workspace
              mountPath: /home/ubuntu
            - name: repo
              mountPath: /root/unidesk
            - name: repo
              mountPath: /app
            - name: codex-config
              mountPath: /root/.codex/config.toml
              readOnly: true
            - name: codex-auth
              mountPath: /root/.codex/auth.json
              readOnly: true
            - name: skills-dir
              mountPath: /root/.agents/skills
              readOnly: true
            - name: ssh-dir
              mountPath: /root/.ssh
              readOnly: true
            - name: logs
              mountPath: /var/log/unidesk
            - name: state
              mountPath: /var/lib/unidesk/code-queue
          readinessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 20
          livenessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
          startupProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 60
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              memory: 1Gi
      volumes:
        - name: docker-sock
          hostPath:
            path: /var/run/docker.sock
            type: Socket
        - name: workspace
          hostPath:
            path: /home/ubuntu
            type: Directory
        - name: repo
          hostPath:
            path: /home/ubuntu/cq-deploy
            type: Directory
        - name: codex-config
          hostPath:
            path: /home/ubuntu/.codex/config.toml
            type: File
        - name: codex-auth
          hostPath:
            path: /home/ubuntu/.codex/auth.json
            type: File
        - name: skills-dir
          hostPath:
            path: /home/ubuntu/.agents/skills
            type: Directory
        - name: ssh-dir
          hostPath:
            path: /home/ubuntu/.ssh
            type: Directory
        - name: logs
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue/logs
            type: DirectoryOrCreate
        - name: state
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue
            type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
  name: code-queue-scheduler
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: scheduler
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: code-queue
    unidesk.ai/instance-id: D601
  ports:
    - name: http
      port: 4222
      targetPort: http
---
apiVersion: v1
kind: Service
metadata:
  name: code-queue-read
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: read
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: read
    unidesk.ai/instance-id: D601-read
  ports:
    - name: http
      port: 4222
      targetPort: http
---
apiVersion: v1
kind: Service
metadata:
  name: code-queue-write
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: write
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/component: write
    unidesk.ai/instance-id: D601-write
  ports:
    - name: http
      port: 4222
      targetPort: http
---
apiVersion: v1
kind: Service
metadata:
  name: d601-provider-egress-proxy
  namespace: unidesk
  labels:
    app.kubernetes.io/name: provider-egress-proxy
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: provider-egress-proxy
    unidesk.ai/provider-id: D601
  ports:
    - name: http
      port: 18789
      targetPort: http
      protocol: TCP
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: d601-provider-egress-proxy
  namespace: unidesk
  labels:
    app.kubernetes.io/name: provider-egress-proxy
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
data:
  provider-egress-proxy.js: |
    const net = require("node:net");

    const listenPort = Number(process.env.PROVIDER_EGRESS_LISTEN_PORT || 18790);
    const upstreamHost = process.env.PROVIDER_EGRESS_UPSTREAM_HOST || "127.0.0.1";
    const upstreamPort = Number(process.env.PROVIDER_EGRESS_UPSTREAM_PORT || 18789);

    function closeBoth(left, right) {
      left.destroy();
      right.destroy();
    }

    net.createServer((client) => {
      const upstream = net.connect({ host: upstreamHost, port: upstreamPort });
      client.pipe(upstream);
      upstream.pipe(client);
      client.on("error", () => closeBoth(client, upstream));
      upstream.on("error", () => closeBoth(client, upstream));
    }).listen(listenPort, "0.0.0.0", () => {
      console.log(JSON.stringify({
        ts: new Date().toISOString(),
        service: "provider-egress-proxy",
        level: "info",
        message: "listening",
        data: { listenPort, upstream: `${upstreamHost}:${upstreamPort}` },
      }));
    });
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: d601-provider-egress-proxy
  namespace: unidesk
  labels:
    app.kubernetes.io/name: provider-egress-proxy
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: provider-egress-proxy
      unidesk.ai/provider-id: D601
  template:
    metadata:
      labels:
        app.kubernetes.io/name: provider-egress-proxy
        app.kubernetes.io/part-of: unidesk
        unidesk.ai/provider-id: D601
        unidesk.ai/node-id: D601
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      nodeSelector:
        unidesk.ai/node-id: D601
      containers:
        - name: provider-egress-proxy
          image: unidesk-code-queue:d601
          imagePullPolicy: IfNotPresent
          command:
            - bun
            - /etc/unidesk-provider-egress/provider-egress-proxy.js
          ports:
            - name: http
              containerPort: 18790
          env:
            - name: PROVIDER_EGRESS_LISTEN_PORT
              value: "18790"
            - name: PROVIDER_EGRESS_UPSTREAM_HOST
              value: "127.0.0.1"
            - name: PROVIDER_EGRESS_UPSTREAM_PORT
              value: "18789"
          volumeMounts:
            - name: script
              mountPath: /etc/unidesk-provider-egress
              readOnly: true
          readinessProbe:
            tcpSocket:
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 12
          livenessProbe:
            tcpSocket:
              port: http
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
      volumes:
        - name: script
          configMap:
            name: d601-provider-egress-proxy
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: d601-tcp-egress-gateway
  namespace: unidesk
  labels:
    app.kubernetes.io/name: tcp-egress-gateway
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
data:
  tcp-egress-gateway.js: |
    const net = require("node:net");

    const proxyUrl = new URL(process.env.TCP_EGRESS_HTTP_PROXY || "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789");
    const proxyHost = proxyUrl.hostname;
    const proxyPort = Number(proxyUrl.port || 80);
    const healthPort = Number(process.env.TCP_EGRESS_HEALTH_PORT || 18080);
    const rawRoutes = process.env.TCP_EGRESS_ROUTES || "";
    const startedAt = new Date().toISOString();

    function positiveInt(value, fallback) {
      const parsed = Number(value);
      return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
    }

    const connectAttempts = positiveInt(process.env.TCP_EGRESS_CONNECT_ATTEMPTS, 8);
    const connectRetryBackoffMs = positiveInt(process.env.TCP_EGRESS_CONNECT_RETRY_BACKOFF_MS, 250);
    const maxEarlyClientBytes = positiveInt(process.env.TCP_EGRESS_MAX_EARLY_CLIENT_BYTES, 1024 * 1024);

    function parseRoute(text) {
      const parts = text.trim().split("=");
      if (parts.length !== 3) throw new Error(`invalid route: ${text}`);
      const [name, listenPortText, target] = parts;
      const [targetHost, targetPortText] = target.split(":");
      const listenPort = Number(listenPortText);
      const targetPort = Number(targetPortText);
      if (!name || !targetHost || !Number.isInteger(listenPort) || !Number.isInteger(targetPort)) throw new Error(`invalid route: ${text}`);
      return { name, listenPort, targetHost, targetPort };
    }

    const routes = rawRoutes.split(",").map((item) => item.trim()).filter(Boolean).map(parseRoute);
    if (routes.length === 0) throw new Error("TCP_EGRESS_ROUTES must define at least one route");

    function findHeaderEnd(buffer) {
      for (let index = 0; index <= buffer.length - 4; index += 1) {
        if (buffer[index] === 13 && buffer[index + 1] === 10 && buffer[index + 2] === 13 && buffer[index + 3] === 10) return index + 4;
      }
      return -1;
    }

    function log(level, message, data = {}) {
      console.log(JSON.stringify({ ts: new Date().toISOString(), service: "tcp-egress-gateway", level, message, data }));
    }

    function pipeViaHttpConnect(client, route) {
      const earlyClientChunks = [];
      let earlyClientBytes = 0;
      let proxy = null;
      let tunnelReady = false;
      let closed = false;
      let attempt = 0;
      let retryTimer = null;

      const cleanupProxy = () => {
        if (proxy === null) return;
        proxy.removeAllListeners();
        proxy.destroy();
        proxy = null;
      };

      const closeBoth = () => {
        if (closed) return;
        closed = true;
        if (retryTimer !== null) clearTimeout(retryTimer);
        client.destroy();
        cleanupProxy();
      };

      const retryOrClose = (reason, data = {}) => {
        cleanupProxy();
        if (!closed && attempt < connectAttempts) {
          const delayMs = Math.min(connectRetryBackoffMs * attempt, 3000);
          log("warn", "connect_retry", { route: route.name, attempt, attempts: connectAttempts, delayMs, reason, ...data });
          retryTimer = setTimeout(() => {
            retryTimer = null;
            startProxy();
          }, delayMs);
          retryTimer.unref?.();
          return;
        }
        log("warn", "connect_rejected", { route: route.name, attempt, attempts: connectAttempts, reason, ...data });
        closeBoth();
      };

      client.on("data", (chunk) => {
        if (tunnelReady && proxy !== null) {
          proxy.write(chunk);
          return;
        }
        earlyClientBytes += chunk.length;
        if (earlyClientBytes > maxEarlyClientBytes) {
          log("warn", "early_client_buffer_limit_exceeded", { route: route.name, bytes: earlyClientBytes, limit: maxEarlyClientBytes });
          closeBoth();
          return;
        }
        earlyClientChunks.push(chunk);
      });
      client.on("error", closeBoth);
      client.on("close", closeBoth);

      const startProxy = () => {
        if (closed) return;
        attempt += 1;
        tunnelReady = false;
        const currentProxy = net.connect({ host: proxyHost, port: proxyPort });
        const proxyHeaderChunks = [];
        proxy = currentProxy;

        currentProxy.on("connect", () => {
          currentProxy.write(`CONNECT ${route.targetHost}:${route.targetPort} HTTP/1.1\r\nHost: ${route.targetHost}:${route.targetPort}\r\n\r\n`);
        });
        currentProxy.on("data", (chunk) => {
          if (currentProxy !== proxy) return;
          if (tunnelReady) {
            client.write(chunk);
            return;
          }
          proxyHeaderChunks.push(chunk);
          const headerBuffer = Buffer.concat(proxyHeaderChunks);
          const headerEnd = findHeaderEnd(headerBuffer);
          if (headerEnd < 0) return;
          const header = headerBuffer.subarray(0, headerEnd).toString("latin1");
          if (!/^HTTP\/1\.[01] 200\b/u.test(header)) {
            const body = headerBuffer.subarray(headerEnd).toString("utf8").slice(0, 300);
            retryOrClose("non_200", { header: header.slice(0, 200), body: body.length > 0 ? body : null });
            return;
          }
          tunnelReady = true;
          const remaining = headerBuffer.subarray(headerEnd);
          if (remaining.length > 0) client.write(remaining);
          for (const early of earlyClientChunks) currentProxy.write(early);
          earlyClientChunks.length = 0;
          earlyClientBytes = 0;
        });
        currentProxy.on("error", (error) => {
          if (currentProxy !== proxy) return;
          retryOrClose("proxy_error", { error: String(error?.message || error) });
        });
        currentProxy.on("close", () => {
          if (currentProxy !== proxy || closed) return;
          if (!tunnelReady) {
            retryOrClose("proxy_closed_before_tunnel");
            return;
          }
          closeBoth();
        });
      };

      startProxy();
    }

    for (const route of routes) {
      net.createServer((client) => pipeViaHttpConnect(client, route)).listen(route.listenPort, "0.0.0.0", () => {
        log("info", "route_listening", { route: route.name, listenPort: route.listenPort, target: `${route.targetHost}:${route.targetPort}`, proxy: `${proxyHost}:${proxyPort}` });
      });
    }

    Bun.serve({
      hostname: "0.0.0.0",
      port: healthPort,
      fetch() {
        return Response.json({ ok: true, service: "tcp-egress-gateway", startedAt, proxy: `${proxyHost}:${proxyPort}`, routes, connectAttempts, connectRetryBackoffMs });
      },
    });
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: d601-tcp-egress-gateway
  namespace: unidesk
  labels:
    app.kubernetes.io/name: tcp-egress-gateway
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: tcp-egress-gateway
      unidesk.ai/provider-id: D601
  template:
    metadata:
      labels:
        app.kubernetes.io/name: tcp-egress-gateway
        app.kubernetes.io/part-of: unidesk
        unidesk.ai/provider-id: D601
        unidesk.ai/node-id: D601
    spec:
      nodeSelector:
        unidesk.ai/node-id: D601
      containers:
        - name: tcp-egress-gateway
          image: unidesk-code-queue:d601
          imagePullPolicy: IfNotPresent
          command:
            - bun
            - /etc/unidesk-tcp-egress/tcp-egress-gateway.js
          ports:
            - name: pg
              containerPort: 15432
            - name: pk01-pg
              containerPort: 25432
            - name: oa
              containerPort: 4255
            - name: health
              containerPort: 18080
          env:
            - name: TCP_EGRESS_HTTP_PROXY
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: TCP_EGRESS_ROUTES
              value: "postgres=15432=74.48.78.17:15432,pk01-postgres=25432=74.48.78.17:15433,oa-event-flow=4255=74.48.78.17:4255"
            - name: TCP_EGRESS_HEALTH_PORT
              value: "18080"
            - name: TCP_EGRESS_CONNECT_ATTEMPTS
              value: "8"
            - name: TCP_EGRESS_CONNECT_RETRY_BACKOFF_MS
              value: "250"
          volumeMounts:
            - name: script
              mountPath: /etc/unidesk-tcp-egress
              readOnly: true
          readinessProbe:
            httpGet:
              path: /health
              port: health
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 12
          livenessProbe:
            httpGet:
              path: /health
              port: health
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
      volumes:
        - name: script
          configMap:
            name: d601-tcp-egress-gateway
---
apiVersion: v1
kind: Service
metadata:
  name: d601-tcp-egress-gateway
  namespace: unidesk
  labels:
    app.kubernetes.io/name: tcp-egress-gateway
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/provider-id: D601
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: tcp-egress-gateway
    unidesk.ai/provider-id: D601
  ports:
    - name: pg
      port: 15432
      targetPort: pg
    - name: pk01-pg
      port: 25432
      targetPort: pk01-pg
    - name: oa
      port: 4255
      targetPort: oa
    - name: health
      port: 18080
      targetPort: health
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: code-queue
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
    unidesk.ai/instance-id: D601
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: code-queue
      unidesk.ai/instance-id: D601
  template:
    metadata:
      labels:
        app.kubernetes.io/name: code-queue
        app.kubernetes.io/part-of: unidesk
        unidesk.ai/deployment-mode: k3sctl-managed
        unidesk.ai/instance-id: D601
        unidesk.ai/node-id: D601
    spec:
      nodeSelector:
        unidesk.ai/node-id: D601
      terminationGracePeriodSeconds: 30
      containers:
        - name: code-queue
          image: unidesk-code-queue:d601
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 4222
          envFrom:
            - secretRef:
                name: code-queue-env
                optional: true
          env:
            - name: HOST
              value: "0.0.0.0"
            - name: PORT
              value: "4222"
            - name: DATABASE_URL
              value: "postgres://unidesk:unidesk_dev_password@d601-tcp-egress-gateway.unidesk.svc.cluster.local:15432/unidesk"
            - name: CODE_QUEUE_INSTANCE_ID
              value: "D601"
            - name: CODE_QUEUE_SERVICE_ROLE
              value: "scheduler"
            - name: CODE_QUEUE_SCHEDULER_ENABLED
              value: "true"
            - name: CODE_QUEUE_SCHEDULER_POLL_INTERVAL_MS
              value: "2000"
            - name: CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED
              value: "false"
            - name: CODE_QUEUE_DATA_DIR
              value: "/var/lib/unidesk/code-queue"
            - name: CODE_QUEUE_WORKDIR
              value: "/workspace"
            - name: CODE_QUEUE_CODEX_HOME
              value: "/var/lib/unidesk/code-queue/codex-home"
            - name: CODE_QUEUE_OPENCODE_XDG_DIR
              value: "/var/lib/unidesk/code-queue/opencode-xdg"
            - name: CODE_QUEUE_SOURCE_CODEX_CONFIG
              value: "/root/.codex/config.toml"
            - name: UNIDESK_SKILLS_PATH
              value: "/root/.agents/skills"
            - name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
              value: "/home/ubuntu/.agents/skills"
            - name: CODE_QUEUE_DEFAULT_MODEL
              value: "gpt-5.5"
            - name: CODE_QUEUE_MODELS
              value: "gpt-5.5,gpt-5.4-mini,gpt-5.4,deepseek-chat,minimax-m3,minimax-m2.7"
            - name: MINIMAX_MODEL
              value: "MiniMax-M3"
            - name: MINIMAX_M3_MODEL
              value: "MiniMax-M3"
            - name: CODE_QUEUE_MODEL_REASONING_EFFORTS
              value: "gpt-5.5=xhigh"
            - name: CODE_QUEUE_SANDBOX
              value: "danger-full-access"
            - name: CODE_QUEUE_APPROVAL_POLICY
              value: "never"
            - name: CODE_QUEUE_MAX_ACTIVE_QUEUES
              value: "0"
            - name: CODE_QUEUE_DATABASE_POOL_MAX
              value: "2"
            - name: NODE_OPTIONS
              value: "--max-old-space-size=1024"
            - name: GIT_CONFIG_COUNT
              value: "1"
            - name: GIT_CONFIG_KEY_0
              value: "safe.directory"
            - name: GIT_CONFIG_VALUE_0
              value: "*"
            - name: CODE_QUEUE_IN_MEMORY_OUTPUT_RECORDS
              value: "10"
            - name: CODE_QUEUE_IN_MEMORY_EVENT_RECORDS
              value: "10"
            - name: CODE_QUEUE_MAIN_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_REMOTE_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EXECUTION_PROVIDER_IDS
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_MASTER_HOST
              value: "74.48.78.17"
            - name: CODE_QUEUE_DEV_CONTAINER_DEFAULT_PROVIDER_ID
              value: "D601"
            - name: CODE_QUEUE_DEV_CONTAINER_WORKDIR
              value: "/home/ubuntu"
            - name: CODE_QUEUE_EGRESS_PROXY_ENABLED
              value: "true"
            - name: CODE_QUEUE_EGRESS_PROXY_URL
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: CODE_QUEUE_EGRESS_PROXY_NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,claudeqq,claudeqq.unidesk,claudeqq.unidesk.svc,claudeqq.unidesk.svc.cluster.local,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,backend-core,oa-event-flow,database,hyueapi.com,.hyueapi.com,api.minimaxi.com,.minimaxi.com"
            - name: HTTP_PROXY
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: HTTPS_PROXY
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: ALL_PROXY
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: http_proxy
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: https_proxy
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: all_proxy
              value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
            - name: NO_PROXY
              value: "localhost,127.0.0.1,::1,host.docker.internal,claudeqq,claudeqq.unidesk,claudeqq.unidesk.svc,claudeqq.unidesk.svc.cluster.local,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,backend-core,oa-event-flow,database,hyueapi.com,.hyueapi.com,api.minimaxi.com,.minimaxi.com"
            - name: no_proxy
              value: "localhost,127.0.0.1,::1,host.docker.internal,claudeqq,claudeqq.unidesk,claudeqq.unidesk.svc,claudeqq.unidesk.svc.cluster.local,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,d601-tcp-egress-gateway,d601-tcp-egress-gateway.unidesk,d601-tcp-egress-gateway.unidesk.svc,d601-tcp-egress-gateway.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,backend-core,oa-event-flow,database,hyueapi.com,.hyueapi.com,api.minimaxi.com,.minimaxi.com"
            - name: OA_EVENT_FLOW_BASE_URL
              value: "http://d601-tcp-egress-gateway.unidesk.svc.cluster.local:4255"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
              value: "true"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL
              value: "http://claudeqq.unidesk.svc.cluster.local:3290"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE
              value: "private"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_USER_ID
              value: "645275593"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_MAX_RESPONSE_CHARS
              value: "12000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TIMEOUT_MS
              value: "15000"
            - name: CODE_QUEUE_NOTIFY_CLAUDEQQ_SEND_ATTEMPTS
              value: "3"
            - name: LOG_FILE
              value: "/var/log/unidesk/code-queue.jsonl"
            - name: UNIDESK_LOG_RETENTION_BYTES
              value: "1GiB"
          volumeMounts:
            - name: docker-sock
              mountPath: /var/run/docker.sock
            - name: workspace
              mountPath: /workspace
            - name: workspace
              mountPath: /home/ubuntu
            - name: repo
              mountPath: /root/unidesk
            - name: repo
              mountPath: /app
            - name: codex-config
              mountPath: /root/.codex/config.toml
              readOnly: true
            - name: codex-auth
              mountPath: /root/.codex/auth.json
              readOnly: true
            - name: skills-dir
              mountPath: /root/.agents/skills
              readOnly: true
            - name: ssh-dir
              mountPath: /root/.ssh
              readOnly: true
            - name: logs
              mountPath: /var/log/unidesk
            - name: state
              mountPath: /var/lib/unidesk/code-queue
          readinessProbe:
            httpGet:
              path: /health
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 20
          livenessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
          startupProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 60
          resources:
            requests:
              cpu: 250m
              memory: 15Gi
            limits:
              memory: 15Gi
      volumes:
        - name: docker-sock
          hostPath:
            path: /var/run/docker.sock
            type: Socket
        - name: workspace
          hostPath:
            path: /home/ubuntu
            type: Directory
        - name: repo
          hostPath:
            path: /home/ubuntu/cq-deploy
            type: Directory
        - name: codex-config
          hostPath:
            path: /home/ubuntu/.codex/config.toml
            type: File
        - name: codex-auth
          hostPath:
            path: /home/ubuntu/.codex/auth.json
            type: File
        - name: skills-dir
          hostPath:
            path: /home/ubuntu/.agents/skills
            type: Directory
        - name: ssh-dir
          hostPath:
            path: /home/ubuntu/.ssh
            type: Directory
        - name: logs
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue/logs
            type: DirectoryOrCreate
        - name: state
          hostPath:
            path: /home/ubuntu/cq-deploy/.state/code-queue
            type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
  name: code-queue
  namespace: unidesk
  labels:
    app.kubernetes.io/name: code-queue
    app.kubernetes.io/part-of: unidesk
    unidesk.ai/deployment-mode: k3sctl-managed
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: code-queue
    unidesk.ai/instance-id: D601
  ports:
    - name: http
      port: 4222
      targetPort: http
